module if_id(
    input clk,
    input reset,
    input [5:0] stall,

    input [31:0] i_inst,
    input [63:0] i_inst_addr,
    input [63:0] i_pc,
    input [63:0] i_badvaddr,
    input [63:0] i_excode,
    input i_except_ena,
    input i_inst_r_valid,
    input flush_if_id,
    input flush,
    input keep,
    input [63:0] new_pc,
    input [63:0] b_j_pc,
    input pcsource,

    output reg [31:0] o_inst,
    output reg [63:0] o_inst_addr,
    output reg [63:0] o_pc,
    output reg [63:0] o_badvaddr,
    output reg [63:0] o_excode,
    output reg o_except_ena,
    output reg o_inst_r_valid
);

    always @(posedge clk) begin
        if(reset) begin
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(flush) begin
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(keep) begin
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(stall[1] == 1'b1 && stall[2] == 1'b0) begin
            o_badvaddr <= 64'd0;
            o_excode <= 64'd0;
            o_except_ena <= 1'b0;
            o_inst_r_valid <= 1'b0;
        end else if(stall[1] == 1'b0 && stall[2] == 1'b0) begin
            if(flush_if_id) begin
                o_badvaddr <= 64'd0;
                o_excode <= 64'd0;
                o_except_ena <= 1'b0;
                o_inst_r_valid <= 1'b0;
            end else begin
                o_badvaddr <= i_badvaddr;
                o_excode <= i_excode;
                o_except_ena <= i_except_ena;
                o_inst_r_valid <= i_inst_r_valid;
            end
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            o_inst <= 32'd0;
            o_inst_addr <= 64'h0000000080000000;
            o_pc <= 64'h0000000080000000;
        end else if(keep) begin
            o_inst <= 32'd0;
            o_inst_addr <= 64'h0000000080000000;
            o_pc <= 64'h0000000080000000;
        end else if(flush) begin
            o_inst <= 32'd0;
            o_inst_addr <= new_pc;
            o_pc <= new_pc;
        end else if(stall[1] == 1'b0 && stall[2] == 1'b0) begin
            if(flush_if_id) begin
                o_inst <= 32'd0;
                o_inst_addr <= pcsource ? b_j_pc : 64'd0;
                o_pc <= pcsource ? b_j_pc : 64'd0;
            end else begin
                o_inst <= i_inst;
                o_inst_addr <= i_inst_addr;
                o_pc <= i_pc;
            end
        end
    end
endmodule
